package modeling;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Dictionary;


/**
 * @author Mathieu Rousseau
 * @email mathieu.rousseau3@mail.mcgill.ca
 */


/** ------------------------------------------------------------------------------------------------------------------
 * start of MCMC5CLOOCV class
 * ------------------------------------------------------------------------------------------------------------------  **/
public class MCMC5CLOOCV {
	
	
	/*  global variables  */
	private static final String inputPath = "MCMC5C/Input/";
	private static final String LOOCVPath = "MCMC5C/LOOCV/";
	private static String IFcompleteList;
	private static boolean[] indicesAllowedToRemove;
	/*  end of global variables  */
	
	
	/*  start of getListOfIndicesToExclude method  */
	private static void getListOfIndicesToExclude(){
		
		//  find the minimum and maximum indices
		String line = null;
		int minIndex = Integer.MAX_VALUE;
		int maxIndex = Integer.MIN_VALUE;
		try{
			BufferedReader br = new BufferedReader(new FileReader(inputPath + IFcompleteList));			
			while((line = br.readLine()) != null){
				String[] values = line.split("\t");
				int index1 = Integer.parseInt(values[0]);
				int index2 = Integer.parseInt(values[1]);
				
				if(index1 < minIndex){
					minIndex = index1;
				}
				if(index2 < minIndex){
					minIndex = index2;
				}
				if(index1 > maxIndex){
					maxIndex = index1;
				}
				if(index2 > maxIndex){
					maxIndex = index2;
				}
			}
			br.close();
		}catch (IOException e) {
			e.printStackTrace();
			System.out.println("Error: cannot find file with filename \"" + IFcompleteList + "\"\n" +
			"System.exit(0)");
			System.exit(0);
		}
//		System.out.println("minIndex = " + minIndex + "\nmaxIndex = " + maxIndex);
		
		
		int[] indicesCount = new int[maxIndex+1];		//  going to index from minIndex to maxIndex (not correcting to start from zero)
		for(int i=minIndex; i<=maxIndex; i++){
			indicesCount[i] = 0;
		}
		
		line = null;
		try{
			BufferedReader br = new BufferedReader(new FileReader(inputPath + IFcompleteList));			
			while((line = br.readLine()) != null){
				String[] values = line.split("\t");
				int index1 = Integer.parseInt(values[0]);
				int index2 = Integer.parseInt(values[1]);
				
				if(index1 == index2){
					System.out.println("Error: a fragments should not have an IF value with itself.\nSystem.exit(0)");
					System.exit(0);
				}
				
				double IF = Double.parseDouble(values[2]);
				if(IF <= 0){
//					System.out.println("ignoring entry " + index1 + "-" + index2 + " because the IF (" + IF + ") is less than or equal to zero (0).");
				}
				else{
					double stdev = Double.parseDouble(values[3]);
					if(stdev <= 0){
//						System.out.println("ignoring entry " + index1 + "-" + index2 + " because the standard deviation (" + stdev + ") is zero (0).");
					}
					else{
						indicesCount[index1]++;
						indicesCount[index2]++;
					}
				}
				
			}
			br.close();
		}catch (IOException e) {
			e.printStackTrace();
			System.out.println("Error: cannot find file with filename \"" + IFcompleteList + "\"\n" +
			"System.exit(0)");
			System.exit(0);
		}
		
		indicesAllowedToRemove = new boolean[maxIndex+1];		//  going to index from minIndex to maxIndex (not correcting to start from zero)
		for(int i=minIndex; i<=maxIndex; i++){
			indicesAllowedToRemove[i] = false;
		}
		for(int i=minIndex; i<=maxIndex; i++){
//			System.out.println(i + "\t" + indicesCount[i]);
			if(indicesCount[i] > 1){
				indicesAllowedToRemove[i] = true;
			}
		}
		
//		for(int i=minIndex; i<=maxIndex; i++){
//			System.out.println(i + "\t" + indicesCount[i] + "\t" + indicesAllowedToRemove[i]);
//		}		
	}/*  end of getListOfIndicesToExclude method  */
	
	
	/*  start of generateLOOCVIFfiles method  */
	private static void generateLOOCVIFfiles(){
		
		//  import all of the candidate IF values and store locally
		//  remove the entries with IF values <= 0 and entries with stdev <= 0
		int originalNumberOfLines = 0;
		ArrayList<String> IForiginalEntriesNonZero = new ArrayList<String>();
		String line = null;
		try{
			BufferedReader br = new BufferedReader(new FileReader(inputPath + IFcompleteList));			
			while((line = br.readLine()) != null){
				originalNumberOfLines++;
				
				String[] values = line.split("\t");
				int index1 = Integer.parseInt(values[0]);
				int index2 = Integer.parseInt(values[1]);
				double IF = Double.parseDouble(values[2]);
				double stdev = Double.parseDouble(values[3]);
				
				if((IF > 0) && (stdev > 0)){
					IForiginalEntriesNonZero.add(line);
				}
				else{
//					System.out.println("excluded entry " + index1 + "-" + index2 + " with IF (" + IF + ") and stdev (" + stdev + ")");
				}
				
			}
			br.close();
		}catch (IOException e) {
			e.printStackTrace();
			System.out.println("Error: cannot find file with filename \"" + IFcompleteList + "\"\n" +
			"System.exit(0)");
			System.exit(0);
		}
		IForiginalEntriesNonZero.trimToSize();
//		System.out.println("number of original entries = " + originalNumberOfLines + "\nnumber of candidate entries = " + IForiginalEntriesNonZero.size());
		
		
		
		//  generate an IF input file for each of the removed entries
		String outputFilenameLOOCVmapping = LOOCVPath + "LOOCV_mapping_" + IFcompleteList;
		try{
			BufferedWriter bwLOOCV = new BufferedWriter(new FileWriter(outputFilenameLOOCVmapping));
		
			int counterOfEntriesLeftOut = 1;				//  make the filename indices start at one (1) instead of zero (0)
			
			for(String entryToLeaveOut: IForiginalEntriesNonZero){
				
				//  make sure that the entry is allowed to be left out (i.e. it is not the only data point for either of its indices
				String values[] = entryToLeaveOut.split("\t");
				int index1 = Integer.parseInt(values[0]);
				int index2 = Integer.parseInt(values[1]);
				
				if(indicesAllowedToRemove[index1] && indicesAllowedToRemove[index2]){
					
					String outputFilenameIF = LOOCVPath + counterOfEntriesLeftOut + "_LOOCV_" + IFcompleteList;
					
					try{						
						BufferedWriter bwIF = new BufferedWriter(new FileWriter(outputFilenameIF));


						for(String currentEntry: IForiginalEntriesNonZero){
							if(!currentEntry.equals(entryToLeaveOut)){					//  write all of the lines except for the entry to leave out
								bwIF.write(currentEntry);
								bwIF.newLine();
								bwIF.flush();
							}
							else{						//  output the entry to leave out to the mapping file
								bwLOOCV.write(counterOfEntriesLeftOut + "\t" + entryToLeaveOut);
								bwLOOCV.newLine();
								bwLOOCV.flush();
							}
						}
						bwIF.flush();
						bwIF.close();
					}catch (IOException e) {
						System.out.println("Error: could not output file: " + outputFilenameIF);
						e.printStackTrace();
					}//end of try-catch block
//					System.out.println("\tOutput file: " + outputFilenameIF);
					
					counterOfEntriesLeftOut++;
				}				
			}
			counterOfEntriesLeftOut--;		//  started the counter at one (1) and incremented after the final iteration of the loop so need to decrement the counter by one
			System.out.println("\tGenerated " + counterOfEntriesLeftOut + " LOOCV IF input files.");
			
		}catch(IOException e){
			System.out.println("Error: could not output file: " + outputFilenameLOOCVmapping);
			e.printStackTrace();
		}//end of try-catch block		
		System.out.println("\tOutput file: " + outputFilenameLOOCVmapping);
		
		
		//  output the original complete IF file
		String outputFilenameOriginal = LOOCVPath + "original_full_" + IFcompleteList;

		try{						
			BufferedWriter bwOriginal = new BufferedWriter(new FileWriter(outputFilenameOriginal));

			for(String currentEntry: IForiginalEntriesNonZero){
				bwOriginal.write(currentEntry);
				bwOriginal.newLine();
				bwOriginal.flush();
			}	
			bwOriginal.flush();
			bwOriginal.close();
		}catch (IOException e) {
			System.out.println("Error: could not output file: " + outputFilenameOriginal);
			e.printStackTrace();
		}//end of try-catch block
		System.out.println("\tOutput file: " + outputFilenameOriginal);
		
	}/*  end of generateLOOCVIFfiles method  */
	
	
	/*  start of main method  */
	public static void main(String[] args) {	

		
		//  specify the original full IF data file
//		IFcompleteList = "IFs_DMSO.txt";
		
		
		//  find out which indices can be excluded in the LOOCV
//		getListOfIndicesToExclude();
		
		
		//  generate all of the LOOCV files, each missing one IF entry
//		generateLOOCVIFfiles();
//		System.exit(0);
		
		
		//  set the parameters for the MCMC5C program
		String filenameIFs, filenameFragments;
		long runLength, numberOfStructuresToOutput;
		double stepSize, exponent;
		
		if(args.length != 9){
			System.out.println("Error: there are not exactly nine (9) arguments.\nSystem.exit(0)");
			System.exit(0);
		}
		
		filenameIFs = args[0];
		filenameFragments = args[1];
//		runLength = (long)1E8;
		runLength = (long)Double.parseDouble(args[2]);
		numberOfStructuresToOutput = (long)Double.parseDouble(args[3]);
//		stepSize = 0.05;
		stepSize = Double.parseDouble(args[4]);
//		exponent = 2;
		exponent = Double.parseDouble(args[5]);
		
		String[] MCMC5Cparameters = new String[6];
		MCMC5Cparameters[0] = filenameIFs;
		MCMC5Cparameters[1] = filenameFragments;
		MCMC5Cparameters[2] = String.valueOf(runLength);
		MCMC5Cparameters[3] = String.valueOf(numberOfStructuresToOutput);
		MCMC5Cparameters[4] = String.valueOf(stepSize);
		MCMC5Cparameters[5] = String.valueOf(exponent);
		
		
		
		int numberOfLOOCVfiles = Integer.parseInt(args[6]);
		int startIndex = Integer.parseInt(args[7]);
		int endIndex = Integer.parseInt(args[8]);
		
		for(int i=startIndex; i<=endIndex; i++){
			String filenameInput = i + "_LOOCV_" + filenameIFs;
			MCMC5Cparameters[0] = filenameInput;
			
			MCMC5C structureGenerator = new MCMC5C();
			structureGenerator.run(MCMC5Cparameters);			
		}		
	}/*  end of main method  */

	
}/*  end of MCMC5CLOOCV class  */